package com.kgar.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kgar.dao.ResumeDao;
import com.kgar.dto.Result;
import com.kgar.dto.UserDTO;
import com.kgar.entity.pojo.*;
import com.kgar.service.AsyncService;
import com.kgar.service.ResumeService;
import com.kgar.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.stream.Stream;

import static com.kgar.util.RedisConstants.CACHE_RESUME_TTL;
import static com.kgar.util.RedisConstants.USER_RESUME_KEY;

@Slf4j
@Service
public class  ResumeServiceImpl extends ServiceImpl<ResumeDao, Resume> implements ResumeService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private AsyncService asyncService;

    @Value("${aliyun.resumeSDK.url}")
    private String url;

    @Value("${aliyun.resumeSDK.appcode}")
    private String appcode;


    @Override
    public Result queryAll() {
        return Result.ok(list());
    }

    /**
     * 根据用户id查询简历草稿
     */
    @Override
    public Result queryByUserId() {
        //获取当前登录用户
        UserDTO user = UserHolder.getUser();
        //获取用户id
        Integer userId = user.getUserId();
        //查询redis中的数据
        List<Object> resumeList = stringRedisTemplate.opsForHash().values(USER_RESUME_KEY + userId);
        //如果redis缓存中不存在简历，则查询数据库
        if (resumeList.isEmpty()) {
            //获取条件选择器
            LambdaQueryWrapper<Resume> wrapper = Wrappers.lambdaQuery(Resume.class);
            //添加条件
            wrapper.eq(Resume::getUserId, userId);
            //通过条件查询结果到list
            List<Resume> list = list(wrapper);
            //如果数据库中有数据，则将redis同步更新
            Map<String, String> resumeMaps = new HashMap<>();
            if (list != null) {
                list.forEach(resume -> {
                    Map<String, Object> map = BeanUtil.beanToMap(resume, new HashMap<>(),
                            CopyOptions.create()
                                    .setFieldValueEditor((fieldName, fieldValue) ->
                                            Objects.requireNonNullElse(fieldValue, "")));
                    String str = JSONUtil.toJsonStr(map);
                    resumeList.add(str);
                    resumeMaps.put(resume.getResumeId().toString(), str);

                });
                //将简历信息保存到redis 的hash表中
                stringRedisTemplate.opsForHash().putAll(USER_RESUME_KEY + userId, resumeMaps);
                stringRedisTemplate.expire(USER_RESUME_KEY + userId, CACHE_RESUME_TTL, TimeUnit.MINUTES);
            }
        }

        List<Resume> collect = resumeList.stream().map(r -> JSONUtil.toBean((String) r, Resume.class)).toList();

        return Result.ok(collect);
    }

    /**
     * 保存简历草稿
     *
     * @param resume 简历
     * @return Result 结果集
     */
    @Override
    public Result saveDraft(Resume resume) {
        UserDTO user = UserHolder.getUser();
        Integer userId = user.getUserId();
        resume.setUserId(userId);
        resume.setSavedTime(new Timestamp(System.currentTimeMillis()));
        StringBuilder sb = new StringBuilder();

        if (resume.getEducationObjs() != null) {

            for (EducationExp educationObj : resume.getEducationObjs()) {
                formatAndAppend(sb, educationObj.getEduMajor());
                formatAndAppend(sb, educationObj.getEduDegree());
                formatAndAppend(sb, educationObj.getEduContent());
            }
        }

        if (resume.getJobExpObjs() != null) {

            for (JobExp jobExp : resume.getJobExpObjs()) {
                formatAndAppend(sb, jobExp.getJobPosition());
                formatAndAppend(sb, jobExp.getJobDept());
                formatAndAppend(sb, jobExp.getJobContent());
                formatAndAppend(sb, jobExp.getJobIndustry());
            }
        }

        if (resume.getProjExpObjs() != null) {

            for (ProjExp projExp : resume.getProjExpObjs()) {
                formatAndAppend(sb, projExp.getProjPosition());
                formatAndAppend(sb, projExp.getProjName());
                formatAndAppend(sb, projExp.getProjContent());
            }
        }

        if (resume.getSkillsObjs() != null) {

            for (Skills skills : resume.getSkillsObjs()) {
                formatAndAppend(sb, skills.getSkillsName());
            }
        }
        formatAndAppend(sb,resume.getContMyDesc());

        resume.setRawText(sb.toString());
        //将数据保存到数据库
        saveOrUpdate(resume);
        //删除redis缓存
        stringRedisTemplate.delete(USER_RESUME_KEY + userId);
        //对简历进行分词并添加标签到数据库
//        asyncService.addTags2Mysql(user,resume);
        // 异步建立知识图谱中用户和简历的关系
        asyncService.createRelationWithUser2Resume(user, resume);

        //异步保存到es搜索引擎中
        asyncService.saveResume2ES(resume);
        //返回响应
        return Result.ok();
    }

    // 新增方法用于简化字符串格式化和追加
    private void formatAndAppend(StringBuilder sb, String value) {
        if (!Objects.equals(value, "")) {
            sb.append(value).append("\n");
        }
    }

    @Override
    public Result parseResume(MultipartFile file) {
        try {
            //提取文件内容
            String s = ReadDocUtil.readDoc(file.getInputStream(), file.getOriginalFilename());
            if (s == null) {
                return Result.fail("无法解析此类型文件!");
            }
            //TODO 解析文件内容
            Resume resume = text2resume(s);
            if (resume == null) {
                return Result.fail("格式错误，解析失败！");
            }
            resume.setUserId(UserHolder.getUser().getUserId());
            //TODO 解析成功，保存简历草稿到redis以及数据库
            saveDraft(resume);
            return Result.ok(resume);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result updateResume(Resume resume) {
        UserDTO user = UserHolder.getUser();
        Integer userId = user.getUserId();
        //更新数据库
        boolean b = updateById(resume);
        if (!b) {
            return Result.fail("更新失败！");
        }
        //删除缓存,根据resumeId删除对应分数的value
        stringRedisTemplate.opsForHash().delete(USER_RESUME_KEY + userId, resume.getResumeId().toString());
        return Result.ok();
    }

    @Override
    public Result deleteById(Integer resumeId) {
        //获取当前登录用户
        UserDTO user = UserHolder.getUser();
        Integer userId = user.getUserId();
        //先删除数据库
        boolean b = removeById(resumeId);
        if (!b) {
            return Result.fail("删除失败！");
        }
        //若数据库删除成功，则删除缓存
        stringRedisTemplate.opsForHash().delete(USER_RESUME_KEY + userId, resumeId.toString());
        //若数据库删除成功，则删除知识图谱
        asyncService.deleteResumeFromNeo4j(resumeId);
        //若数据库删除成功，则删除es
        asyncService.deleteResumeFromES(resumeId);

        return Result.ok();

    }

    @Override
    public Result parseResumeV2(MultipartFile file) {
        try {
            //用第三方api解析简历并返回json数据
            JSONObject jsonObject = ResumeParseUtil.resumeParser(file.getOriginalFilename(), file.getBytes(), url, appcode);

            if (jsonObject.getByPath("status.code", Integer.class) != 200) {
                return Result.fail("解析失败");
            }
            // 解析json数据转为bean对象
            Resume resume = jsonObject.get("result", Resume.class);
            ResumeTags resumeTags = jsonObject.get("tags", ResumeTags.class);
            resume.setTags(resumeTags);
            int index = Objects.requireNonNull(file.getOriginalFilename()).lastIndexOf(".");
            resume.setResumeName(file.getOriginalFilename().substring(0,index));

            System.out.println(resume);
            //返回结果数据
            return Result.ok(resume);

        } catch (Exception e) {
            return Result.fail("解析失败,类型转换错误");
        }
    }

    private static Resume text2resume(String text) {
        Resume resume = new Resume();
        int count = 0;
        String name = TextParseUtil.getStrName(text);
        String gender = TextParseUtil.getGender(text);
        String phone = TextParseUtil.pickUpPhoneNo(text);
        String email = TextParseUtil.pickUpEmail(text);
        String birth = TextParseUtil.pickUpBrith(text);
        if (name != null) {
            resume.setName(name);
            count++;
        }
        if (gender != null) {
            resume.setGender("男".equals(gender));
            count++;
        }
        if (email != null) {
            resume.setEmail(email);
            count++;
        }
        if (birth != null) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
            count++;
            try {
                Date parse = format.parse(birth);
                resume.setBirthday(new java.sql.Date(parse.getTime()));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }

        }
        if (phone != null) {
            resume.setPhone(phone);
            count++;
        }
        if (count < 3) {
            return null;
        } else
            return resume;
    }

}
